package core

import (
	"bytes"
	"encoding/binary"
	"errors"
)

// 主题消息
type TopicMessage struct {
	TopicName string
	MessageID uint64 // QoS>0时需要
	Payload   []byte
	QoS       uint8 // 0,1,2
	Retain    uint8 // 保留消息标志
}

func NewPublishMessage(topicName string, payload []byte, qos uint8, retain uint8) *TopicMessage {
	return &TopicMessage{
		TopicName: topicName,
		MessageID: GetNanoID(),
		Payload:   payload,
		QoS:       qos,
		Retain:    retain,
	}
}
func EncodePublishAckMessage(msgID uint64) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	if err := bufs.WriteByte(MQ_PubAck); err != nil {
		return nil, err
	}
	if _, err := WriteUint64(bufs, msgID); err != nil {
		return nil, err
	}
	return bufs.Bytes(), nil
}
func DecodePublishAckMessage(data []byte) (uint64, error) {
	if len(data) < 9 {
		return 0, errors.New("data too short to decode PublishAckMessage")
	}

	if data[0] != MQ_PubAck {
		return 0, errors.New("invalid message type")
	}

	return binary.BigEndian.Uint64(data[1:9]), nil
}
func EncodePublishMessage(msg *TopicMessage) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	bufs.Grow(18 + len(msg.Payload) + len(msg.TopicName))

	if err := bufs.WriteByte(MQ_Pub); err != nil {
		return nil, err
	}

	if _, err := WriteUint64(bufs, msg.MessageID); err != nil {
		return nil, err
	}

	if _, err := WriteString(bufs, msg.TopicName); err != nil {
		return nil, err
	}

	if _, err := WriteBytes(bufs, msg.Payload); err != nil {
		return nil, err
	}

	if err := bufs.WriteByte(msg.QoS); err != nil {
		return nil, err
	}
	if err := bufs.WriteByte(msg.Retain); err != nil {
		return nil, err
	}

	return bufs.Bytes(), nil
}
func EncodeFinishAckMessage(msgid uint64, topicName string) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	if err := bufs.WriteByte(MQ_FinishAck); err != nil {
		return nil, err
	}
	if _, err := WriteUint64(bufs, msgid); err != nil {
		return nil, err
	}
	if _, err := WriteString(bufs, topicName); err != nil {
		return nil, err
	}
	return bufs.Bytes(), nil
}
func DecodePublishMessage(data []byte) (*TopicMessage, error) {
	if len(data) < 10 { // 至少需要MQ_Pub标志 + MessageID(8字节) + TopicName长度(4字节) + QoS(1字节)
		return nil, errors.New("data too short to decode PublishMessage")
	}

	msg := &TopicMessage{}

	if data[0] != MQ_Pub {
		return nil, errors.New("invalid message type")
	}

	msg.MessageID = binary.BigEndian.Uint64(data[1:9])
	topicLen := binary.BigEndian.Uint32(data[9:13])
	if len(data) < int(13+topicLen+1) { // 13 + TopicName长度 + QoS
		return nil, errors.New("data too short for topic name")
	}

	msg.TopicName = string(data[13 : 13+topicLen])

	msg.Payload = data[17+topicLen : len(data)-2] // 最后两个字节是QoS和Retain标志

	msg.QoS = data[len(data)-2]
	msg.Retain = data[len(data)-1]

	return msg, nil
}

// 点对点消息
type P2PMessage struct {
	SenderClientID uint64
	TargetClientID uint64
	MessageID      uint64
	Payload        []byte
	QoS            uint8
	Retain         uint8
}

func NewP2PMessage(senderid, targetid uint64, buf []byte, qos uint8, retain uint8) *P2PMessage {
	return &P2PMessage{SenderClientID: senderid, TargetClientID: targetid, MessageID: GetNanoID(),
		Payload: buf, QoS: qos, Retain: retain}
}
func EncodeP2PMessage(msg *P2PMessage) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)
	bufs.Grow(30 + len(msg.Payload))

	if err := bufs.WriteByte(MQ_P2P); err != nil {
		return nil, err
	}

	if _, err := WriteUint64(bufs, msg.SenderClientID); err != nil {
		return nil, err
	}
	if _, err := WriteUint64(bufs, msg.TargetClientID); err != nil {
		return nil, err
	}
	if _, err := WriteUint64(bufs, msg.MessageID); err != nil {
		return nil, err
	}

	if _, err := WriteBytes(bufs, msg.Payload); err != nil {
		return nil, err
	}

	if err := bufs.WriteByte(msg.QoS); err != nil {
		return nil, err
	}
	if err := bufs.WriteByte(msg.Retain); err != nil {
		return nil, err
	}

	return bufs.Bytes(), nil
}
func DecodeP2PMessage(data []byte) (*P2PMessage, error) {
	if len(data) < 26 { // 至少需要MQ_Pub标志 + MessageID(8字节) + TopicName长度(4字节) + QoS(1字节)
		return nil, errors.New("data too short to decode onebyonemessage")
	}

	msg := &P2PMessage{}

	if data[0] != MQ_P2P {
		return nil, errors.New("invalid message type")
	}
	msg.SenderClientID = binary.BigEndian.Uint64(data[1:9])
	msg.TargetClientID = binary.BigEndian.Uint64(data[9:17])
	msg.MessageID = binary.BigEndian.Uint64(data[17:25])
	msg.Payload = data[25+4 : len(data)-2] // 最后两个字节是QoS和Retain标志
	msg.QoS = data[len(data)-2]
	msg.Retain = data[len(data)-1]

	return msg, nil
}
func DecodeOneByOneAckMessage(data []byte) (uint64, error) {
	if len(data) < 9 {
		return 0, errors.New("data too short to decode onebyoneackmessage")
	}

	if data[0] != MQ_P2PAck {
		return 0, errors.New("invalid message type")
	}

	return binary.BigEndian.Uint64(data[1:9]), nil
}
